package ;

/**
 * ...
 * @author Mike
 */


import de.polygonal.ds.mem.FloatMemory;
import de.polygonal.motor2.geom.math.Mat22;
import flash.display.Bitmap;
import flash.display.Loader;
import flash.display.Shader;
import flash.display.Sprite;
import flash.display.Stage3D;
import flash.display.StageScaleMode;
import flash.display3D.Context3D;
import flash.display3D.Context3DProgramType;
import flash.display3D.Context3DRenderMode;
import flash.display3D.Context3DTextureFormat;
import flash.display3D.IndexBuffer3D;
import flash.display3D.Program3D;
import flash.display3D.textures.Texture;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Matrix;
import flash.geom.Matrix3D;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.errors.Error;
import flash.display.BitmapData;
import flash.geom.Vector3D;
import flash.Vector;
import flash.Vector;
import flash.display3D.Context3DBlendFactor;
import flash.geom.PerspectiveProjection;
import flash.geom.Orientation3D;
import haxe.Log;

@:shader({
	var input : {
		pos : Float3,
		index : Float
	};
	var tuv : Float;

	
	function vertex( mpos : M44, mscale: M44, mproj : M44, uvs : Array4<Float>  ) {
		//var tx = offset.x * sin(offset.z) * dis;
		//var ty = offset.y * cos(offset.z)* dis;
		//var g = uvs[ pos.w ];
		tuv =  uvs[ index ];
		var ipos = pos.xyzz;
		out = ( ipos ) * mpos * mscale * mproj;
	}

	function fragment( tex : Texture ) {
		out = [0.0, 1.0, 0.0, tuv];
	}
}) class Shader extends format.hxsl.Shader {

}

class MainSprite extends Sprite 
{
	private static function makeOrthoProjection(w:Float, h:Float, n:Float, f:Float):Matrix3D
	{
		return new Matrix3D(Vector.ofArray([
			2/w, 0  ,       0,        0,
			0  , 2/h,       0,        0,
			0  , 0  , 1/(f-n), -n/(f-n),
			0  , 0  ,       0,        1]));
	}
	
	private static var W:Int = 1024;
	private static var H:Int = 1024;
	
	private var bitmap:BitmapData;
	private var _context3D:Context3D;
	private var _shaderProgram:Program3D;
	private var _indexBuffer:IndexBuffer3D;
	private var _sprite:MoleSprite;
	private var _texture:Texture;
	private var texturePage:Texture;
	private var shader : Shader;
	private var drawToTexturePageShader : Shader;
	private var loader : Loader;
	var timeClick : Float;
	public function new() 
	{
		super();
		//loader = new Loader();
		//loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderComplete);
		//loader.load( new flash.net.URLRequest( "./molepeople.jpg" ) );
	}
	
	function loaderComplete(event:Event)
	{
		bitmap = event.target.content.bitmapData;
		
		stage.scaleMode = StageScaleMode.NO_SCALE;
		var stage3D:Stage3D = stage.stage3Ds[0];
		stage3D.addEventListener( Event.CONTEXT3D_CREATE, initialize);
		stage.addEventListener( MouseEvent.CLICK, click);
		stage3D.requestContext3D(Std.string(Context3DRenderMode.AUTO));
		
	}
	
	private function initialize(e:Event):Void 
	{
		var stage3D:Stage3D = cast(e.target, Stage3D);
		
		_context3D = stage3D.context3D;
		
		if (_context3D == null)
		{
			trace("oh no, context is null!");
			return;
		}
		
		haxe.Log.trace(_context3D.driverInfo);
		try
		{

			_context3D.configureBackBuffer(W, H, 2, true);		
			_context3D.enableErrorChecking = true;
			_context3D.setDepthTest( true, flash.display3D.Context3DCompareMode.LESS_EQUAL );
			_context3D.setCulling( flash.display3D.Context3DTriangleFace.NONE );
			_context3D.setBlendFactors( Context3DBlendFactor.SOURCE_COLOR , Context3DBlendFactor.DESTINATION_ALPHA );	
	
			_texture = _context3D.createTexture( 1024, 1024, Context3DTextureFormat.BGRA,false);
			_texture.uploadFromBitmapData( bitmap );
			
			bitmap.dispose();
			loader.unload();
			bitmap = null;
			loader = null;
	
			// Create backing store
			//texturePage = _context3D.createTexture( 2048 , 2048, Context3DTextureFormat.BGRA, true);
			
			shader = new Shader( _context3D );
			
			//drawToTexturePageShader = new Shader( _context3D );

			_sprite = new MoleSprite( _context3D );			
			shader.bind( _sprite.getVertexBuffer() );
			addEventListener( Event.ENTER_FRAME, renderFrame );	
			
		
		}
		catch (e:Error)
		{
			trace(e);
		}		
		stage3D.removeEventListener( Event.CONTEXT3D_CREATE, initialize);
	}
	
	private function click( e:MouseEvent ) {
		timeClick = flash.Lib.getTimer() / 500;
	
	}
	
	private function renderFrame(e:Event):Void
	{
		var timeSec:Float = timeClick - flash.Lib.getTimer() / 500;

	
		_context3D.clear( 0, 0, 0, 1, 0 );


		//build mvp matrix
		var mvp:Matrix3D = _sprite.getWorldTransform();

		//flip y-axis so it points down and shift origin to upper-left corner
		var scaleMatrix : Matrix3D = new Matrix3D(Vector.ofArray(
			[
			 1.0, 0.0, 0.0, 0.0
			,0.0, -1.0, 0.0, 0.0
			,0.0, 0.0, 1.0, 0.0
			,0.0, 0.0, 0, 1.0
			]
		));
		var uv  : Array<Float> = new Array<Float>();
		
		for ( t in 0...4){
		uv.push( t );
		}
		
		
		var st = scaleMatrix.clone();

				shader.init(	
				{ 
					mpos : mvp, mscale: scaleMatrix , mproj : makeOrthoProjection( W, H, 90,901), uvs: uv },
					{ tex : _texture }
				);	
				_sprite.draw( shader );

		_context3D.present();

	}
}